/**   
* @Title: HttpClientPoolManager.java 
* @Package cn.comytst.data.integration.http 
* @Description: TODO(用一句话描述该文件做什么) 
* @author 123774135@qq.com 
* @date 2019年1月25日 下午2:33:49 
* @version V1.0   
*/
package cn.com.ytst.data.integration.util.http;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContexts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**
 * @ClassName: HttpClientPoolManager
 * @Description:
 * @author 123774135@qq.com
 * @date 2019年1月25日 下午2:33:49
 * 
 */
@Component("httpClientPoolManager")
public class HttpClientPoolManager {

	//CONNECTION_TIMEOUT，因此一定要设置
	public static final Long CONN_MANAGER_TIMEOUT = 500L; //该值就是连接不够用的时候等待超时时间，一定要设置，而且不能太大 ()
	
	@Value("${max_total_pool}")
	private int maxTotalPool;

	@Value("${max_con_per_route}")
	private int maxConPerRoute;

	@Value("${socket_timeout}")
	private int socketTimeout;

	@Value("${connection_request_timeout}")
	private int connectionRequestTimeout;

	@Value("${connect_timeout}")
	private int connectTimeout;

	private Logger logger = LoggerFactory.getLogger(HttpClientPoolManager.class);

	@Bean(name = "poolingHttpClientConnectionManager")
	public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager() {
		PoolingHttpClientConnectionManager poolConnManager = null;
		try {
			SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
			HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, hostnameVerifier);
			Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
					.register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslsf).build();
			poolConnManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
			// Increase max total connection to 200
			poolConnManager.setMaxTotal(maxTotalPool);
			// Increase default max connection per route to 20
			poolConnManager.setDefaultMaxPerRoute(maxConPerRoute);
			SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(socketTimeout).build();
			poolConnManager.setDefaultSocketConfig(socketConfig);
		} catch (Exception e) {
			logger.error("InterfacePhpUtilManager init Exception" + e.toString());
		}
		return poolConnManager;
	}

	@Bean(name = "closeableHttpClient")
	public CloseableHttpClient closeableHttpClient() {
		PoolingHttpClientConnectionManager poolConnManager = poolingHttpClientConnectionManager();
		RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectionRequestTimeout)
				.setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();
		// 请求重试处理
	    HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
	        public boolean retryRequest(IOException exception,
	                                    int executionCount, HttpContext context) {
	            if (executionCount >= 2) {// 如果已经重试了5次，就放弃
	                return false;
	            }
	            if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接，那么就重试
	                return true;
	            }
	            if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
	                return false;
	            }
	            if (exception instanceof InterruptedIOException) {// 超时
	                return false;
	            }
	            if (exception instanceof UnknownHostException) {// 目标服务器不可达
	                return false;
	            }
	            if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
	                return false;
	            }
	            if (exception instanceof SSLException) {// SSL握手异常
	                return false;
	            }

	            HttpClientContext clientContext = HttpClientContext
	                    .adapt(context);
	            HttpRequest request = clientContext.getRequest();
	            // 如果请求是幂等的，就再次尝试
	            if (!(request instanceof HttpEntityEnclosingRequest)) {
	                return true;
	            }
	            return false;
	        }
	    };
	    ConnectionKeepAliveStrategy kaStrategy = new DefaultConnectionKeepAliveStrategy()
        {
            @Override
            public long getKeepAliveDuration(HttpResponse response, HttpContext context)
            {
                long keepAlive = super.getKeepAliveDuration(response, context);
                if (keepAlive == -1)
                {
                    keepAlive = 60000;
                }
                return keepAlive;
            }

        };

	    CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(poolConnManager)
				.setDefaultRequestConfig(requestConfig).setRetryHandler(httpRequestRetryHandler).setKeepAliveStrategy(kaStrategy).build();
		if (poolConnManager != null && poolConnManager.getTotalStats() != null) {
			logger.info("now client pool " + poolConnManager.getTotalStats().toString());
		}
		return httpClient;
	}

	// /**
	// *
	// * @Title: get @Description: get请求 @param @param path @param @param
	// * clazz @param @return 设定文件 @return T 返回类型 @throws
	// */
	// public String get(String path) {
	// CloseableHttpClient httpClient = getConnection();
	// HttpGet httpget = new HttpGet(path);
	// CloseableHttpResponse response = null;
	//
	// try {
	// response = httpClient.execute(httpget);
	// HttpEntity entity = response.getEntity();
	// String result = EntityUtils.toString(entity, "utf-8");
	// return result;
	// } catch (IOException e) {
	// e.printStackTrace();
	// } finally {
	// closed(response);
	// }
	// return "";
	// }
	//
	//
	// private static void setPostParams(HttpPost httpost,
	// Map<String, Object> params) {
	// List<NameValuePair> nvps = new ArrayList<NameValuePair>();
	// Set<String> keySet = params.keySet();
	// for (String key : keySet) {
	//
	// nvps.add(new BasicNameValuePair(key, params.get(key).toString()));
	// }
	// try {
	// httpost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
	// } catch (UnsupportedEncodingException e) {
	// e.printStackTrace();
	// }
	// }
	//
	//
	// /**
	// * POST请求URL获取内容
	// *
	// * @param url
	// * @return
	// * @author SHANHY
	// * @throws IOException
	// * @create 2015年12月18日
	// */
	// public String post(String url, Map<String, Object> params) throws IOException
	// {
	// HttpPost httppost = new HttpPost(url);
	//
	// setPostParams(httppost, params);
	// CloseableHttpResponse response = null;
	// try {
	// response = getConnection().execute(httppost,
	// HttpClientContext.create());
	// HttpEntity entity = response.getEntity();
	// String result = EntityUtils.toString(entity, "utf-8");
	// EntityUtils.consume(entity);
	// return result;
	// } catch (Exception e) {
	//// e.printStackTrace();
	// throw e;
	// } finally {
	// closed(response);
	// }
	// }
	//
	//
	// private void closed(CloseableHttpResponse response) {
	// if (response != null) {
	// try {
	// response.close();
	// } catch (IOException e) {
	// e.printStackTrace();
	// }
	// }
	// }
	//
	// public static void main(String[] args) {
	//
	// }

}
